import os

from PyQt6.QtWidgets import QFrame

from .Constant import *
from .DBR import DBR
from .Catalog import Catalog, deal_catalog
from Utils.DiskUtils import read_bytes_16, deal_file_name
from Utils.CommonUtils import mkdir, mk_file
from pojo.Disk import Disk
from pojo.File import File
from MessageBox.ProcessingBox import ProcessingBox


class EXFAT(Disk):
    def __init__(self, path: str):
        """
        初始化EXFAT对象
        :param path: 磁盘路径
        """
        super().__init__()
        if path is None or len(path) < 1:
            return
        self.file_log = []  # 文件列表
        self.current_cluster = None  # 当前簇号
        self.per_cluster_of_sectors = None  # 每簇扇区数
        self.f = open(r'\\.\%s' % path, 'rb')  # 以二进制只读模式打开文件

        self.__init_basic_read()  # 初始化基本读取
        self.__construct_read(self.root_catalog.log_list)  # 构建文件目录结构

    def save(self, f: File, path: str):
        f: File
        data = self.search_data(f)
        mk_file(path, f.name)
        with open(path + "\\" + f.name, "wb") as file:
            file.write(data)
            file.flush()
            file.close()

    def write_to_path(self, f: list[File], path: str, process: ProcessingBox):
        try:
            for i in f:
                trace = path + "\\" + i.name
                if i.file_type == IS_FOLDER:
                    mkdir(path, i.name)
                    if i.hasChildren():
                        process.set_offset(int(process.offset / len(i.getFiles())))
                        if len(i.getFiles()) > 0:
                            for j in i.getFiles():
                                j: File
                                self.save(j, trace)
                                process.set_value()
                        if len(i.getFolders()) > 0:
                            process.set_offset(int(process.offset / len(i.getFolders())))
                            self.write_to_path(i.getFolders(), trace, process)
                else:
                    self.save(i, path)
        except Exception as e:
            process.e = str("异常信息：" + str(e))
            process.res = SAVE_FAIL

    def search_data(self, f: File) -> bytes:
        self.go_to(f.local)
        data = self.f.read(f.size)
        self.f.seek(-f.size, 1)
        return data

    def __init_basic_read(self):
        """
        初始化基本读取
        """
        self.DBR = DBR(self.f.read(SECTOR).hex())  # 读取DBR
        self.back_to_cluster_table_data = self.DBR.get_cluster_origin() * SECTOR  # 获取簇表的起始位置

        self.back_to_cluster_table()  # 将文件指针移动到簇表的起始位置

        self.current_cluster = self.DBR.get_root_catalog_number()  # 获取根目录簇号
        self.per_cluster_of_sectors = int(self.DBR.get_per_cluster_of_sectors())  # 获取每簇扇区数

        skip = (self.current_cluster - 2) * self.per_cluster_of_sectors
        self.f.read(skip * SECTOR)  # 跳过根目录簇之前的簇

        root_catalog_data = self.f.read(SECTOR).hex()
        root_catalog_data = self.read_file_total(root_catalog_data)  # 读取根目录完整数据

        self.root_catalog = Catalog(root_catalog_data)  # 创建根目录Catalog对象

    def back_to_cluster_table(self):
        """
        将文件指针移动到簇表的起始位置
        """
        self.f.seek(self.back_to_cluster_table_data, os.SEEK_SET)
        self.current_cluster = 2

    def read_file_total(self, data: str):
        """
        读取完整文件数据
        :param data: 初始数据
        :return: 完整数据
        """
        next_data = self.f.read(SECTOR).hex()

        while int(next_data[:16 * 2], 16) != 0:
            data += next_data
            next_data = self.f.read(SECTOR).hex()
        self.back_to_cluster_table()
        return data

    def go_to(self, n: str):
        """
        将文件指针移动到指定簇的位置
        :param n: 簇号
        """
        self.f.read((int(n) - self.current_cluster) * self.per_cluster_of_sectors * SECTOR)
        self.current_cluster = n

    def __construct_read(self, root_catalog: list[str], file: File = None):
        """
        构建文件目录结构
        :param root_catalog: 根目录文件列表
        :param file: 当前文件对象
        """
        for folder in root_catalog:
            name = deal_file_name(folder[16 * 4 * 2:])
            if name in NOT_READ_FOLDER:
                continue
            capacity = read_bytes_16(folder[5 * 8 * BYTES:5 * 8 * BYTES + 8])
            local = read_bytes_16(folder[(6 * 8 + 4) * BYTES:(6 * 8 + 4) * BYTES + 4])
            file_type = read_bytes_16(folder[4 * BYTES: 4 * BYTES + 2])
            data = File(name, capacity, local, file_type, file if file is None else file.name)

            if file is None:
                self.file_log.append(data)
            else:
                if data.file_type == IS_FOLDER:
                    file.getFolders().append(data)
                else:
                    file.getFiles().append(data)
        if file is None:
            self._deep_read(self.file_log)
        else:
            self._deep_read(file.children)

    def _deep_read(self, file: list[File] or dict):
        """
        递归读取文件数据
        :param file: 文件列表
        """
        data: list[File] = []
        if isinstance(file, dict):
            data = file['folders']
        else:
            data = file
        for i in data:
            self.go_to(i.local)
            if i.file_type == IS_FOLDER:
                log_data = self.f.read(SECTOR).hex()
                log_data = self.read_file_total(log_data)
                if log_data[:2] == "85":
                    log_list = deal_catalog(log_data)
                    self.__construct_read(log_list, i)
                else:
                    continue
            else:
                # i.data = log_data[:i.size * BYTES]
                print(f"{i.name} 已读取完成")
                continue
